<template>
  <div class="code-box">
    <h3 class="code-box-title">1、shallowRef和shallowReactive的使用(点击按钮切换响应类型)</h3>
    <p>shallow只会监听数据的第一层级，当数据结构比较复杂时，使用shallowRef和shallowReactive能提高性能。</p>
    <p>shallowRef和shallowReactive的区别：shallowRef只有value属性有响应式，shallowReactive只有第一层的所有属性具有响应式</p>
    <button class="btn" @click="switchType('ref')" :class="{ active: isRef == 'ref' }">切换为ref</button>
    <button class="btn" @click="switchType('shallowRef')"
      :class="{ active: isRef == 'shallowRef' }">切换为shallowRef</button>
    <button class="btn" @click="switchType('reactive')" :class="{ active: isRef == 'reactive' }">切换为reactive</button>
    <button class="btn" @click="switchType('shallowReactive')"
      :class="{ active: isRef == 'shallowReactive' }">切换为shallowReactive</button>
    <div style="margin: 12px 0;">
      <button class="btn" @click="changeStr">change str</button>
      {{ baseTamp }}字符串类型：{{ str }}
    </div>
    <div>
      <div style="border: 1px solid #ddd; padding: 10px; margin: 12px 0;">
        {{ isRef }}对象类型：
        <p>{{ obj }}</p>
      </div>
      <button class="btn" @click="changeName">change name</button>
      <button class="btn" @click="changeLocationX">change location.x</button>
      <button class="btn" @click="changeLocationValue">change location</button>
      <button class="btn" @click="changeObj">change all Obj</button>
    </div>
  </div>
</template>

<script lang='ts' setup>
import { ref, shallowRef, reactive, shallowReactive } from 'vue';

// 初始化必须执行一边这四个方法，否则eval执行报错
const q1 = ref(1);
const q2 = shallowRef(1);
const q3 = reactive({});
const q4 = shallowReactive({});

console.log(q1, q2, q3, q4);

/**
 * 通过 __v_isShallow 为 true 的标记，来判断是否是浅层的响应式对象。
 * 只有当数据结构比较简单时，才可以使用 shallowRef 和 shallowReactive。
 * 简单的数据结构包括：字符串、数字、布尔值、数组、对象。
 * 当数据结构比较复杂时，建议使用 ref 和 reactive。
 * shallowRef 和 shallowReactive 的区别：
 * 1. shallowRef 是一个只读的响应式对象，它的初始值是不可变的，但是它的属性值是可变的。
 * 2. shallowReactive 是一个可变的响应式对象，它的初始值是可变的，但是它的属性值是不可变的。
 * 3. shallowRef 和 shallowReactive 的主要区别在于，当数据结构比较复杂时，shallowRef 能提高性能，因为它不会深入到每个属性的层级。
 * 4. 什么时候使用 shallowRef 和 shallowReactive？
 * 一般情况下，如果数据结构比较简单，可以使用 ref 和 reactive。
 * 如果数据结构比较复杂，可以使用 shallowRef 和 shallowReactive。 
 * 例如，当我们需要一个只读的响应式对象，但是它的属性值是可变的，可以使用 shallowRef。
*/
const isRef = ref('ref');
const baseTamp = ref("ref")
let str: any = null;
let obj: any = null;

let isHaveValue = true
const switchType = (type: string) => {
  isRef.value = type;
  isHaveValue = type.toLowerCase().includes('ref');
  if (isHaveValue) {
    str = eval(`${isRef.value}("Hello")`)
    baseTamp.value = type;
  }
  obj = eval(isRef.value)({ name: 'jack', age: 20, location: { x: 1.2, y: 25.12 } })

  // console.log(`切换响应类型为${type}`);
  // console.log('---------------------------------------');
  // console.log('str:', str);
  // console.log('obj:', obj);
}

switchType(isRef.value) // 初始化时，默认使用 ref 类型 生成数据

const changeStr = () => {
  str.value += "-world"
}

const changeName = () => {
  (isHaveValue && obj.value || obj).name += "~"
}

const changeLocationX = () => {
  (isHaveValue && obj.value || obj).location.x += 2
}

const changeLocationValue = () => {
  (isHaveValue && obj.value || obj).location = { x: 77.77, y: 66.66 }
}
const changeObj = () => {
  if (isHaveValue) {
    obj.value = { name: 'Tom', age: 35, location: { x: 999, y: 111 } }
  } else {
    Object.assign(obj, { name: 'Tom', age: 35, location: { x: 999, y: 111 } })
  }

}


// const str = shallowRef("hello")
// const obj = shallowReactive({ name: 'jack', age: 20, location: { x: 1.2, y: 25.12 } })

// const changeStr = () => {
//   str.value += "-world"
// }

// const changeName = () => {
//   obj.name += "~"
// }

// const changeLocationX = () => {
//   obj.location.x += 2
// }

// const changeLocationValue = () => {
//   obj.location = { x: 77.77, y: 66.66 }
// }
// const changeObj = () => {
//   Object.assign(obj, { name: 'Tom', age: 35, location: { x: 999, y: 111 } })
// }
</script>

<style scoped lang='scss'>
.code-box {
  border: 1px solid #ddd;
  padding: 10px;
  margin-bottom: 20px;
  min-height: 50px;

  &-title {
    border-bottom: 1px solid #ddd;
    padding-bottom: 20px;
  }
}

.btn.active {
  background-color: #f0a80d;
  color: #fff;
}
</style>
